package org.third.common.utils.rest;
//package com.hp.ccue.identity.rest;
//
//import org.codehaus.jackson.JsonEncoding;
//import org.codehaus.jackson.JsonGenerator;
//import org.codehaus.jackson.JsonProcessingException;
//import org.codehaus.jackson.map.ObjectMapper;
//import org.codehaus.jackson.map.SerializationConfig;
//import org.codehaus.jackson.map.type.TypeFactory;
//import org.codehaus.jackson.type.JavaType;
//import org.slf4j.Logger;
//import org.slf4j.LoggerFactory;
//import org.springframework.http.HttpInputMessage;
//import org.springframework.http.HttpOutputMessage;
//import org.springframework.http.MediaType;
//import org.springframework.http.converter.AbstractHttpMessageConverter;
//import org.springframework.http.converter.GenericHttpMessageConverter;
//import org.springframework.http.converter.HttpMessageNotReadableException;
//import org.springframework.http.converter.HttpMessageNotWritableException;
//import org.springframework.utilities.Assert;
//
//import java.io.IOException;
//import java.io.InputStream;
//import java.lang.reflect.Type;
//import java.nio.charset.Charset;
//
///**
// * Drop-in replacement for {@link org.springframework.http.converter.json.MappingJackson2HttpMessageConverter} that
// * performs additional logging when incoming JSON code cannot be parsed.
// */
//public class JsonMessageConverter
//        extends AbstractHttpMessageConverter<Object>
//        implements GenericHttpMessageConverter<Object> {
//    /** Logging support */
//    private static final Logger logger = LoggerFactory.getLogger(JsonMessageConverter.class);
//
//    /** Default character set */
//    public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
//
//    /**
//     * Constructs a new instance of JsonMessageConverter.
//     */
//    public JsonMessageConverter() {
//        super(new MediaType("application", "json", DEFAULT_CHARSET),
//                new MediaType("application", "+json", DEFAULT_CHARSET));
//    }
//
//    /** The Jackson ObjectMapper to use for importing and exporting objects as JSON */
//    private ObjectMapper objectMapper = new ObjectMapper();
//
//    /**
//     * Retrieves the underlying {@link ObjectMapper} for this message converter. If not set by the
//     * {@link #setObjectMapper(org.codehaus.jackson.map.ObjectMapper)} method, returns a default instance of
//     * {@link ObjectMapper}.
//     *
//     * @return the {@link HibernateAwareObjectMapper} object supporting this message converter.
//     */
//    public ObjectMapper getObjectMapper() {
//        return this.objectMapper;
//    }
//
//    /**
//     * Sets the {@link ObjectMapper} object for this message converter. By default, the object mapper is set to a
//     * default instance of {@link ObjectMapper}. Providing an {@link ObjectMapper} instance here gives the client more
//     * control over JSON serialization and deserialization.
//     *
//     * @param mapper the Jackson {@link ObjectMapper} instance to use.
//     */
//    public void setObjectMapper(ObjectMapper mapper) {
//        Assert.notNull(mapper, "ObjectMapper must not be null");
//        this.objectMapper = mapper;
//        configurePrettyPrint();
//    }
//
//    /** Flag that indicates whether to prefix JSON output to prevent JSON hijacking */
//    private boolean prefixJson = false;
//
//    /**
//     * Gets a flag that indicates whether to prefix JSON output with "{} &&" to prevent JSON hijacking.
//     *
//     * @return {@code true} if JSON output should be prefixed to prevent JSON hijacking; {@code false} otherwise.
//     */
//    public boolean getPrefixJson() {
//        return this.prefixJson;
//    }
//
//    /**
//     * Sets a flag that indicates whether the JSON output by this message converter should be prefixed with
//     * "{} &&" to prevent JSON hijacking (default is {@code false}).
//     *
//     * @param prefixJson {@code true} if the JSON output from this message converter should be prefixed to prevent
//     *                   JSON hijacking; {@code false} otherwise.
//     */
//    public void setPrefixJson(boolean prefixJson) {
//        this.prefixJson = prefixJson;
//    }
//
//    /** Flag that indicates whether to perform pretty printing */
//    private Boolean prettyPrint;
//
//    /**
//     * Gets a flag that indicates whether to use the {@link org.codehaus.jackson.utilities.DefaultPrettyPrinter} when
//     * serializing objects to JSON.
//     *
//     * @return the pretty print setting. May be {@code null}.
//     */
//    public Boolean getPrettyPrint() {
//        return this.prettyPrint;
//    }
//
//    /**
//     * Sets a flag that indicates whether to use the  {@link org.codehaus.jackson.utilities.DefaultPrettyPrinter} when
//     * serializing objects to JSON. The default value for this flag is {@code false}.
//     *
//     * @param prettyPrint {@code true} if the JSON output by this message converter should be broken up into multiple
//     *                    lines with indentation; {@code false} otherwise.
//     */
//    public void setPrettyPrint(boolean prettyPrint) {
//        this.prettyPrint = prettyPrint;
//        configurePrettyPrint();
//    }
//
//    /**
//     * Configures the {@link ObjectMapper} object's pretty printing serialization setting based on the value of
//     * {@code #prettyPrint}.
//     */
//    private void configurePrettyPrint() {
//        if(this.prettyPrint != null) {
//            this.objectMapper.configure(SerializationConfig.Feature.INDENT_OUTPUT, this.prettyPrint);
//        }
//    }
//
//    /**
//     * Determines whether this message converter can deserialize the given type from the given media type.
//     *
//     * @param clazz the Java class being deserialized.
//     * @param mediaType the media type of the data being deserialized into a Java class
//     *
//     * @return {@code true} if the Java class can be deserialized from the given media type; {@code false} otherwise.
//     */
//    @Override
//    public boolean canRead(Class<?> clazz, MediaType mediaType) {
//        return canRead(clazz, null, mediaType);
//    }
//
//    /**
//     * Determines whether this message converter can deserialize the given type from the given media type.
//     *
//     * @param type the Java class being deserialized.
//     * @param contextClass the Java class containing {@code type}
//     * @param mediaType the media type of the data being deserialized into a Java class
//     *
//     * @return {@code true} if the Java class can be deserialized from the given media type; {@code false} otherwise.
//     */
//    public boolean canRead(Type type, Class<?> contextClass, MediaType mediaType) {
//        JavaType javaType = getJavaType(type, contextClass);
//        return (this.objectMapper.canDeserialize(javaType) && canRead(mediaType));
//    }
//
//    /**
//     * Determines whether this message converter can serialize the given type to the given media type.
//     *
//     * @param clazz the Java class being serialized
//     * @param mediaType the media type to be produced
//     *
//     * @return {@code true} if the Java class can be serialized to the given media type; {@code false} otherwise.
//     */
//    @Override
//    public boolean canWrite(Class<?> clazz, MediaType mediaType) {
//        return (this.objectMapper.canSerialize(clazz) && canWrite(mediaType));
//    }
//
//    /**
//     * Determines whether this message converter can serialize and deserialize the given Java class. Since
//     * {@link #canRead} and {@link #canWrite} are both overridden, this method need not be implemented. Invoking it
//     * always throws a {@link UnsupportedOperationException}.
//     *
//     * @param clazz the Java class to evaluate
//     *
//     * @return {@link true} if this message converter can serialize and deserialize {@code clazz}; {@code false}
//     * otherwise.
//     */
//    @Override
//    protected boolean supports(Class<?> clazz) {
//        // Should not be called, since we override canRead and canWrite instead
//        throw new UnsupportedOperationException();
//    }
//
//    /**
//     * Deserializes the given {@link HttpInputMessage} to a Java class.
//     *
//     * @param clazz the Java class of the output.
//     * @param inputMessage the HTTP message that contains the JSON text to be deserialized
//     *
//     * @return an object of the given Java class that encapsulates the representation provided in the JSON text.
//     *
//     * @throws IOException if the HTTP message cannot be read
//     * @throws HttpMessageNotReadableException if the contents of the HTTP message cannot be interpreted as a valid JSON
//     * representation of the given Java class.
//     */
//    @Override
//    protected Object readInternal(Class<?> clazz, HttpInputMessage inputMessage)
//            throws IOException, HttpMessageNotReadableException {
//        JavaType javaType = getJavaType(clazz, null);
//        return readJavaType(javaType, inputMessage);
//    }
//
//    /**
//     * Deserializes the given {@link HttpInputMessage} to a Java class.
//     *
//     * @param type the Java class of the output.
//     * @param contextClass the Java class containing {@code type}
//     * @param inputMessage the HTTP message that contains the JSON text to be deserialized
//     *
//     * @return an object of the given Java class that encapsulates the representation provided in the JSON text.
//     *
//     * @throws IOException if the HTTP message cannot be read
//     * @throws HttpMessageNotReadableException if the contents of the HTTP message cannot be interpreted as a valid JSON
//     * representation of the given Java class.
//     */
//    public Object read(Type type, Class<?> contextClass, HttpInputMessage inputMessage)
//            throws IOException, HttpMessageNotReadableException {
//        JavaType javaType = getJavaType(type, contextClass);
//        return readJavaType(javaType, inputMessage);
//    }
//
//    /**
//     * Reads the contents of an {@link InputStream} into a {@link String}
//     *
//     * @param stream the stream
//     *
//     * @return a {@link String} that contains the contents of {@code stream}, interpreted as UTF-8 characters.
//     */
//    private String slurp(InputStream stream) {
//        StringBuilder builder = new StringBuilder();
//        int blockSize = 256;
//        byte[] block = new byte[blockSize];
//        try {
//            int numBytes = stream.read(block);
//            while(numBytes >= 0) {
//                String blockStr = new String(block, "UTF-8");
//                if(numBytes < blockSize) {
//                    blockStr = blockStr.substring(0, numBytes);
//                }
//                builder.append(blockStr);
//                numBytes = stream.read(block);
//            }
//            return builder.toString();
//        } catch(IOException ignore) {
//            return "";
//        }
//    }
//
//    /**
//     * Deserializes the given {@link HttpInputMessage} to a Java class.
//
//     * @param javaType the Java class of the output
//     * @param inputMessage the HTTP message that contains the JSON text to be deserialized
//     *
//     * @return an object of the given Java class that encapsulates the representation provided in the JSON text.
//     */
//    private Object readJavaType(JavaType javaType, HttpInputMessage inputMessage) {
//        try {
//            InputStream stream = inputMessage.getBody();
//            return this.objectMapper.readValue(stream, javaType);
//        } catch(IOException ex) {
//            try {
//                InputStream stream = inputMessage.getBody();
//                stream.reset();
//                String inputJson = slurp(stream);
//                logger.debug("Unable to read JSON: " + inputJson);
//            } catch(IOException ex2) {
//                logger.debug("Invalid message body");
//            }
//            throw new HttpMessageNotReadableException("Could not read JSON: " + ex.getMessage(), ex);
//        }
//    }
//
//    /**
//     * Serializes the given object to JSON text in the given {@link HttpOutputMessage}.
//     *
//     * @param object the Java object to serialize to JSON
//     * @param outputMessage the HTTP message to receive the JSON text in its body
//     *
//     * @throws IOException if an error occurs while writing the JSON text or if a JSON error occurs.
//     * @throws HttpMessageNotWritableException if the message cannot be written.
//     */
//    @Override
//    protected void writeInternal(Object object, HttpOutputMessage outputMessage)
//            throws IOException, HttpMessageNotWritableException {
//        JsonEncoding encoding = getJsonEncoding(outputMessage.getHeaders().getContentType());
//        JsonGenerator jsonGenerator =
//                this.objectMapper.getJsonFactory().createJsonGenerator(outputMessage.getBody(), encoding);
//
//        // Workaround for JsonGenerator objects not applying serialization features.
//        // https://github.com/FasterXML/jackson-databind/issues/12
//        if(this.objectMapper.getSerializationConfig().isEnabled(SerializationConfig.Feature.INDENT_OUTPUT)) {
//            jsonGenerator.useDefaultPrettyPrinter();
//        }
//
//        try {
//            if(this.prefixJson) {
//                jsonGenerator.writeRaw("{} && ");
//            }
//            this.objectMapper.writeValue(jsonGenerator, object);
//        } catch(JsonProcessingException ex) {
//            throw new HttpMessageNotWritableException("Could not write JSON: " + ex.getMessage(), ex);
//        }
//    }
//
//    /**
//     * Gets the {@link JavaType} from the given type and optional context class.
//     *
//     * @param type a Java class object
//     * @param contextClass the Java class that contains the class referenced in {@code type}. May be {@code null}.
//     *
//     * @return the {@link JavaType} for the given type.
//     */
//    protected JavaType getJavaType(Type type, Class<?> contextClass) {
//        TypeFactory factory = TypeFactory.defaultInstance();
//        JavaType contextType = (contextClass != null ? factory.constructType(contextClass) : null);
//        JavaType typeType = factory.constructType(type);
//        return (contextClass != null ? factory.constructType(type, contextType) : typeType);
//    }
//
//    /**
//     * Determines the character encoding to use when serializing to the given media type. Defaults to UTF-8.
//     *
//     * @param contentType The media type
//     *
//     * @return the character encoding for the character set associated with the given media type. If no character set
//     * is specified or if no matching encoding can be found, returns {@link JsonEncoding#UTF8}. Never returns
//     * {@code null}.
//     */
//    protected JsonEncoding getJsonEncoding(MediaType contentType) {
//        if(contentType != null && contentType.getCharSet() != null) {
//            Charset charset = contentType.getCharSet();
//            for(JsonEncoding encoding : JsonEncoding.values()) {
//                if(charset.name().equals(encoding.getJavaName())) {
//                    return encoding;
//                }
//            }
//        }
//
//        return JsonEncoding.UTF8;
//    }
//}
